//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.IO.Packaging;
using System.Threading;
using System.Windows.Media.Imaging;
using OpenLS.Core.Serialization;

namespace OpenLS.Drawing
{
    sealed class BlipData
    {
        public string _extension;
        public byte[] _rawData;
        private BitmapSource _source;

        public BlipData(BitmapSource source)
        {
            this.Source = source;
        }

        public BlipData(byte [] data, string extension)
        {
            this._rawData = data;
            this._extension = extension;
        }

        public BlipData()
        {
            
        }

        public BitmapSource Source
        {
            get { return _source; }
            set
            {
                _source = value;
            }
        }

        public void ReadStream(Stream stream, string extension)
        {
            try
            {
                if (extension != ".wmf" && extension != ".emf")
                {
                    var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat,
                                                       BitmapCacheOption.OnLoad);
                    Source = decoder.Frames[0]; 
                }
            }
            catch (Exception)
            { }
            finally
            {
                stream.Position = 0;
                _extension = extension;
                _rawData = new byte[stream.Length];
                stream.Read(_rawData, 0, _rawData.Length);
            }
        }

        public Uri WriteBlipData(WriteContext parentContext, WriteContext currentContext)
        {
            if (Source != null)
            {
                return writeStream(parentContext, currentContext);
            }
            else if (_rawData != null)
            {
                var blipUri = parentContext.GetAvailableUri("../media/image{0}" + _extension);
                var blipPart = currentContext.Part.Package.CreatePart(blipUri, "image/" + _extension); //\\OK?
                var rel =
                    parentContext.Part.CreateRelationship(blipUri, TargetMode.Internal,
                                                          OfficeConstants.ImageRelationshipType);
                using (var stream = blipPart.GetStream())
                {
                    stream.Write(_rawData, 0, _rawData.Length);
                }
                return blipUri;
            }
            return null;
        }

        internal BitmapEncoder GetEncoder()
        {
            Contract.Ensures(Contract.Result<BitmapEncoder>() != null);
            if (Source is BitmapFrame)
            {
                var f = (BitmapFrame)Source;
                if (f.Decoder != null)
                {
                    return BitmapEncoder.Create(f.Decoder.CodecInfo.ContainerFormat);
                }
            }
            return new PngBitmapEncoder();
        }

        Uri writeStream(WriteContext context, WriteContext c)
        {
            BitmapEncoder encoder = GetEncoder();
            var blipUri = context.GetAvailableUri("../media/image{0}" + encoder.CodecInfo.FileExtensions.Split(',')[0]);
            var blipPart = context.Part.Package.CreatePart(blipUri, encoder.CodecInfo.MimeTypes.Split(',')[0]);
            var rel = context.Part.CreateRelationship(blipUri, TargetMode.Internal,   OfficeConstants.ImageRelationshipType);
            try
            {
                BitmapFrame f = BitmapFrame.Create(Source);
                encoder.Frames.Add(f);
                using (var stream = blipPart.GetStream())
                {
                    encoder.Save(stream);
                }
            }
            catch
            {
                using (var stream = blipPart.GetStream())
                {
                    stream.Write(_rawData, 0, _rawData.Length);;
                }
            }
            return blipUri;
        }

        public byte[] GetBytes()
        {
            Contract.Ensures(Contract.Result<byte []>() != null);
            if (_rawData != null)
                return _rawData;
            if (Source != null)
            {
                var encoder = GetEncoder();
                encoder.Frames.Add(BitmapFrame.Create(Source));
                using (var stream = new MemoryStream())
                {
                    encoder.Save(stream);
                    stream.Flush();
                    stream.Position = 0;
                    byte [] result = new byte[stream.Length];
                    stream.Read(result, 0, result.Length);
                    return result;
                }
            }
            throw new NotSupportedException();
        }
    }
}